﻿using RakutenProxy.Model.NopCommerce;
using RakutenProxy.Model.Rakuten;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace RakutenProxy.DataConverter
{
    public class RakNopProductAttributeValueConverter : RakNopDataConverter<Model.Rakuten.ProductAttributeValue, Model.NopCommerce.ProductVariantAttributeValue>
    {
        public RakNopProductAttributeValueConverter(DbContext sourceDbContext, DbContext targetDbContext)
            : base(sourceDbContext, targetDbContext)
        {
        }

        protected override Model.NopCommerce.ProductVariantAttributeValue GetObjectFromSource(Model.Rakuten.ProductAttributeValue source)
        {
            var rakDbContext = (RakutenDbContext)SourceContext;

            var productAttributeMap = rakDbContext.Product_ProductAttribute_Mappings.FirstOrDefault(m => m.ProductAttributeId == source.ProductAttributeId);
            var rakNopMap = rakDbContext.Rakuten_NopCommerce_Product_ProductAttributeMapping_Maps.FirstOrDefault(m => m.Rakuten_Product_ProductAttribute_Mapping_Id == productAttributeMap.Id);
            
            if (rakNopMap == null)
            {
                throw new ArgumentException("Not mapped product attribute");
            }

            var nopAttributeValue = new Model.NopCommerce.ProductVariantAttributeValue();

            nopAttributeValue.ProductVariantAttributeId = rakNopMap.Nop_Product_ProductAttribute_Mapping_Id;
            nopAttributeValue.AttributeValueTypeId = 0;
            nopAttributeValue.Name = Translate(source.Name);

            return nopAttributeValue;
        }

        protected override void UpdateObjectFromSource(Model.NopCommerce.ProductVariantAttributeValue target, Model.Rakuten.ProductAttributeValue source)
        {
            target.Name = Translate(source.Name);
        }

        public override void Migrate()
        {
            var rakDbContext = (RakutenDbContext)SourceContext;
            var nopDbContext = (NopCommerceEntities)TargetContext;

            var mappedRakIds = rakDbContext.Rakuten_NopCommerce_ProductAttribteValue_Maps.Select(m => m.RakutenProductAttributeValueId);
            var notMappedAttributeValues = rakDbContext.ProductAttributeValues.Where(a => !mappedRakIds.Contains(a.Id));
            var mappedAtttributeValues = rakDbContext.ProductAttributeValues.Except(notMappedAttributeValues);

            foreach (var attributeValue in notMappedAttributeValues)
            {
                var nopAttributeValue = GetObjectFromSource(attributeValue);
                nopDbContext.ProductVariantAttributeValues.Add(nopAttributeValue);
                nopDbContext.SaveChanges();
                var map = new Rakuten_NopCommerce_ProductAttribteValue_Map { RakutenProductAttributeValueId = attributeValue.Id, NopCommerceProductAttributeValueId = nopAttributeValue.Id };
                rakDbContext.Rakuten_NopCommerce_ProductAttribteValue_Maps.Add(map);
            }

            foreach (var attributeValue in mappedAtttributeValues)
            {
                var map = rakDbContext.Rakuten_NopCommerce_ProductAttribteValue_Maps.FirstOrDefault(m => m.RakutenProductAttributeValueId == attributeValue.Id);
                if (map != null)
                {
                    var nopAttributeValue = nopDbContext.ProductVariantAttributeValues.FirstOrDefault(m => m.Id == map.NopCommerceProductAttributeValueId);
                    if (nopAttributeValue != null && !attributeValue.Equals(nopAttributeValue))
                    {
                        UpdateObjectFromSource(nopAttributeValue, attributeValue);
                    }
                }
            }

            rakDbContext.SaveChanges();
            nopDbContext.SaveChanges();
        }

        public override void MigrateOneRecord(int id)
        {
            var rakDbContext = (RakutenDbContext)SourceContext;
            var nopDbContext = (NopCommerceEntities)TargetContext;

            var rakAttributeValue = rakDbContext.ProductAttributeValues.FirstOrDefault(a => a.Id == id);


            if (rakAttributeValue == null)
                return;
            var map = rakDbContext.Rakuten_NopCommerce_ProductAttribteValue_Maps.FirstOrDefault(m => m.RakutenProductAttributeValueId == id);
            if (map == null)
            {
                var nopAttributeValue = GetObjectFromSource(rakAttributeValue);
                nopDbContext.ProductVariantAttributeValues.Add(nopAttributeValue);
                nopDbContext.SaveChanges();
                map = new Rakuten_NopCommerce_ProductAttribteValue_Map { RakutenProductAttributeValueId = rakAttributeValue.Id, NopCommerceProductAttributeValueId = nopAttributeValue.Id };
                rakDbContext.Rakuten_NopCommerce_ProductAttribteValue_Maps.Add(map);
                rakDbContext.SaveChanges();
            }
            else
            {
                var nopAttributeValue = nopDbContext.ProductVariantAttributeValues.FirstOrDefault(a => a.Id == map.NopCommerceProductAttributeValueId);
                if (nopAttributeValue != null)
                {
                    UpdateObjectFromSource(nopAttributeValue, rakAttributeValue);
                    nopDbContext.SaveChanges();
                }
            }
        }

        public override void RemoveOneRecord(int id)
        {
            var rakDbContext = (RakutenDbContext)SourceContext;
            var nopDbContext = (NopCommerceEntities)TargetContext;

            var map = rakDbContext.Rakuten_NopCommerce_ProductAttribteValue_Maps.FirstOrDefault(m => m.RakutenProductAttributeValueId == id);
            if (map == null)
                return;

            var nopAttributeValue = nopDbContext.ProductVariantAttributeValues.FirstOrDefault(a => a.Id == map.NopCommerceProductAttributeValueId);
            if (nopAttributeValue != null)
            {
                nopDbContext.ProductVariantAttributeValues.Remove(nopAttributeValue);
            }

            rakDbContext.Rakuten_NopCommerce_ProductAttribteValue_Maps.Remove(map);

            rakDbContext.SaveChanges();
            nopDbContext.SaveChanges();
        }
    }
}